#!/usr/bin/perl -wc

package RFCMail::Util::NetEnd;

use strict;
use Socket;
use RFCMail::ESMTP::Grammar::Base qw(IPV4_ADDR_LIT_RE);


sub new {
    my $class = shift;
    my %self;
    @self{qw(addr port)} = @_;
    return (bless \%self, $class);
}


sub from_text {
    my ($class, $addr) = @_;
    $addr =~ /\A(@{[IPV4_ADDR_LIT_RE]})(?::(\d+))?\z/o
	or return (undef);
    return (new($class, inet_aton($1), $2));
}


sub from_sockaddr {
    my ($class, $sockaddr) = @_;
    my ($port, $addr) = defined($sockaddr) ? unpack_sockaddr_in($sockaddr) : (undef, undef);
    return (new($class, $addr, $port));
}


sub from_local {
    my ($class, $sock) = @_;
    return (from_sockaddr($class, getsockname($sock)));
}


sub from_peer {
    my ($class, $sock) = @_;
    return (from_sockaddr($class, getpeername($sock)));
}


sub as_text {
    my ($self) = @_;
    my $text = $self->address;
    $text .= ":".$self->port
	if $self->port;
    return ($text);
}


sub as_sockaddr {
    my ($self) = @_;
    return (undef)
	if not defined($self->{port}) or not defined($self->{addr});
    return (pack_sockaddr_in($self->{port}, $self->{addr}));
}


sub name {
    my ($self) = @_;
    return (undef)
	if not defined($self->{addr});
    return (scalar gethostbyaddr($self->{addr}, AF_INET));
}


sub address {
    my ($self) = @_;
    return (undef)
	if not defined($self->{addr});
    return (inet_ntoa($self->{addr}));
}


sub addr { $_[0]->{addr} }


sub port { $_[0]->{port} }


1;
